package dl.bukkit.myststus.vexshow;

import dl.bukkit.myststus.function.condition.ICondition;
import dl.bukkit.myststus.function.ComponentManager;
import dl.bukkit.myststus.function.trigger.Trigger;
import dl.bukkit.myststus.function.trigger.TriggerHud;
import dl.bukkit.myststus.hook.PlaceholderAPIHook;
import dl.bukkit.myststus.library.ats.GComponent;
import dl.bukkit.myststus.logger.Logger;
import lk.vexview.api.VexViewAPI;
import lk.vexview.hud.VexImageShow;
import lk.vexview.hud.VexShow;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;

import java.util.*;

public abstract class AbstractVexHud {
    private final String key;
    private final String url;
    private final String x;
    private final String y;
    private final int w;
    private final int h;
    private final int z;
    private final int time;
    private final List<String> triggers;
    private final Map<ICondition, String> conditions = new HashMap<>();

    private final Map<String, Map<String, Object>> debugMap = new LinkedHashMap<>();

    public AbstractVexHud(String k, YamlConfiguration section) {
        this(
                k,
                section.getString(Attribute.BACKGROUND_URL),
                section.getString(Attribute.LOCATION_X),
                section.getString(Attribute.LOCATION_Y),
                section.getInt(Attribute.SIZE_WIDTH),
                section.getInt(Attribute.SIZE_HEIGHT),
                section.getInt(Attribute.PRIORITY_Z),
                section.getInt(Attribute.SHOW_TIME),
                section.getStringList(Attribute.TRIGGERS),
                getMap(section, Attribute.CONDITIONS)
        );
        debugYaml();
    }

    private AbstractVexHud(String key, String url, String x, String y, int w, int h, int z, int time, List<String> strings, Map<String, String> map) {
        this.key = key;
        this.url = url;
        this.x = x;
        this.y = y;
        this.w = w;
        this.h = h;
        this.z = z;
        this.time = time;
        this.triggers = strings == null ? new ArrayList<>() : strings;
        for (Map.Entry<String, String> entry : map.entrySet()) {
            ICondition condition = ComponentManager.getCondition(entry.getKey());
            if (condition == null) break;
            this.conditions.put(condition,  entry.getValue());
        }
        addConfigDebug("url", url);
        addConfigDebug("x", x);
        addConfigDebug("y", y);
        addConfigDebug("z", z);
        addConfigDebug("width", w);
        addConfigDebug("height", h);
        addConfigDebug("time", time);
        addConfigDebug("triggers", triggers);
    }

    /* Debug */
    public void addConfigDebug(String key, Object value) {
        debugMap.computeIfAbsent("§a" + this.key + "详细信息: ", t -> new LinkedHashMap<>()).put("  §3" + key + ": §f", value);
    }

    public void debugYaml() {
        for (Map.Entry<String, Map<String, Object>> entry : debugMap.entrySet()) {
            Logger.debug(entry.getKey());
            for (Map.Entry<String, Object> objectEntry : entry.getValue().entrySet()) {
                Logger.debug(objectEntry.getKey(), objectEntry.getValue());
            }
        }
    }


    /* Loader */
    public void loadTrigger() {
        Logger.debug("§6[§a", key ,"§6]§a开始载入触发器: ");
        triggers.forEach(s -> {
            Trigger<?> trigger = ComponentManager.getTrigger(s);
            Logger.debug("  §3触发器: §f", s);
            String str = "×";
            if (trigger instanceof TriggerHud) {
                TriggerHud<?> trHud = (TriggerHud<?>) trigger;
                trHud.addHud(this);
                str = "√";
            }
            Logger.debug("  §3是否成功载入: §f", str);
        });
    }

    public boolean isRun(Player player) {
        for (Map.Entry<ICondition, String> entry : conditions.entrySet()) {
            if (! entry.getKey().isRun(player, entry.getValue())) {
                GComponent annotation = entry.getKey().getClass().getAnnotation(GComponent.class);
                Logger.debug("§6[§a", key, "§6]的条件限制[§a", annotation.key(), "§6]不满足于 §a", entry.getValue());
                return false;
            }
        }
        return true;
    }

    public abstract List<VexShow> getVexShowList(Player player, Entity target);

    public final void sendHud(Player player, Entity target) {
        if (isRun(player))
            getVexShowList(player, target).forEach(hud -> VexViewAPI.sendHUD(player, hud));
    }

    public final void removeHud(Player player, Entity target) {
        getVexShowList(player, target).forEach(hud -> VexViewAPI.removeHUD(player, hud.getID()));
    }

    public String getKey() {
        return key;
    }

    public String getId() {
        return "DL.MS." + getClass().getSimpleName().toUpperCase() + "." + getKey().toUpperCase();
    }

    public String getUrl(Player player) {
        return PlaceholderAPIHook.toString(player, url);
    }

    public int getX(Player player) {
        return  Attribute.toValue(player, x, this);
    }

    public int getY(Player player) {
        return Attribute.toValue(player, y, this);
    }

    public int getW() {
        return w;
    }

    public int getH() {
        return h;
    }

    public int getZ() {
        return z;
    }

    public int getTime() {
        return time;
    }

    public VexShow getVexShow(Player player, int index, int x, int y, int w, int h) {
        return new VexImageShow(getId() + index, getUrl(player), getZ(), x, y, w, h, w, h, getTime());
    }

    public VexShow getVexShow(Player player, int x, int y, int w, int h) {
        return new VexImageShow(getId(), getUrl(player), x, y, getZ(), w, h, w, h, getTime());
    }

    public VexShow getVexShow(Player player) {
        return getVexShow(player, getX(player), getY(player), getW(), getH());
    }

    private static Map<String, String> getMap(YamlConfiguration yaml, String str) {
        Map<String, String> map = new HashMap<>();
        if (yaml.isConfigurationSection(str)) {
            for (String key : yaml.getConfigurationSection(str).getKeys(false)) {
                map.put(key, yaml.getString(str + "." + key));
            }
        }
        return map;
    }
}
